package plugin;

import java.io.FileInputStream;
import java.util.ArrayList;
import java.util.Observable;



import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;

public class BarcodeFinderRegistry extends Observable implements Runnable 
{

	private ArrayList<IBarcodeFinder> pluginList;
	private String configFileLocation;
	
	private String description;
	private String barcode;
	
	private volatile boolean running;
	
	public BarcodeFinderRegistry()
	{
		running = false;
		description = "";
		barcode = "";
		
		configFileLocation = "product-identifiers.xml";
		pluginList = new ArrayList<IBarcodeFinder>();
		
		loadPlugins();
	}
	

	/**
	 * Loads the configuration file information so that the objects
	 * can be loaded using reflection
	 */
	private void loadPlugins()
	{
		
		try
		{
			DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
			DocumentBuilder parser = factory.newDocumentBuilder();
			Document doc = parser.parse( new FileInputStream(configFileLocation) );
			
			NodeList identifiers = doc.getElementsByTagName("identifier");
			
			for (int i=0; i< identifiers.getLength(); i++)
			{
				String tmp = identifiers.item(i).getAttributes().getNamedItem("class").getTextContent();
				pluginList.add( getPlugIn(tmp) );
			}
		
		}
		catch (Exception e)
		{
			e.printStackTrace();
		}
	}
	
	private IBarcodeFinder getPlugIn(String name)
	{
		IBarcodeFinder  finder = null;;
		try
		{
			finder = (IBarcodeFinder)Class.forName(name).newInstance();
		} 
		catch (Exception e)
		{
			e.printStackTrace();
		} 
		
		return finder;
	}
	
	/**
	 * Returns the description of the product if it is found in
	 * one of the plug-ins or it returns an empty string 
	 * @param the barcode of the product to search for
	 * @return the description of the product or the empty string
	 */
	public String findDescription(String barcode)
	{
		running = true;
		
		String result = "";
				
		for (IBarcodeFinder finder : pluginList)
		{
			if (!running)
				break;
			
			result = finder.getDescription(barcode);
			
			if (!result.equals(""))
				break;
		}
		
		running = false;
		return result;
	}
	
	public void setBarcode(String bc)
	{
		barcode = bc;
	}
	
	public void stopSearch()
	{
		running = false;
	}
	
	public boolean searching()
	{
		return running;
	}
	
	@Override
	public void run()
	{
		description = findDescription(barcode);
		
		this.setChanged();
		this.notifyObservers(description);
	}	
	
}
